# -*- coding: utf-8 -*-

'''
/**
 * @file        git_pull_xml.py
 * @brief       用于代替repo同时拉取多个仓库
 * @note        1. 直接在命令行中输入python git_pull_xml.py -b basepath -x xmlpath
 *              2. basepath: 本地用于拉取的基础目录
 *              3. xmlpath:  标记仓库的xml文件路径
 * @note        XXXX
 * @author      靳普诏(puzhao.jin@hopechart.com)
 * @date        2025/04/09
 * @version     1.0

 * @par         修改日志
 * <table>
 * <tr><th>Date         <th>Version     <th>Author      <th> Description
 * <tr><td>2025/04/09   <td>1.0         <td>靳普诏       <td> 创建初始版本
 * @copyright   xxxx
 */
'''

import sys
import os
import argparse

from datetime import datetime
# 获取当前日期
CURR_DATE_STRING = datetime.now().strftime("%Y-%m-%d")
# 获取当前时间
CURR_TIME_STRING = datetime.now().strftime("%H:%M:%S")
## 获取当前脚本所在的目录
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
# 输出目录路径
# print("SCRIPT_DIR: "+ SCRIPT_DIR)



def GitPullXml(basepath, xmlpath):
    """
    从XML文件中读取仓库信息并执行git pull操作
    
    Args:
        basepath (str): 本地仓库的基础目录路径
        xmlpath (str): 包含仓库信息的XML文件路径
    
    Returns:
        None
    """
    import xml.etree.ElementTree as ET
    import subprocess
    import os

    # 初始化统计计数器
    total_projects = 0
    success_count = 0
    fail_count = 0
    fail_repos = []

    # 解析XML文件
    tree = ET.parse(xmlpath)
    root = tree.getroot()

    # 获取所有remote信息，使用字典存储
    remotes = {}
    for remote in root.findall('remote'):
        remote_name = remote.get('name')
        remote_fetch = remote.get('fetch')
        remotes[remote_name] = remote_fetch

    # 获取默认remote配置
    default = root.find('default')
    default_remote = default.get('remote')
    default_revision = default.get('revision', 'master')
    
    # 遍历所有未被注释的project节点
    for project in root.findall('project'):
        total_projects += 1
        try:
            project_path = project.get('path')
            project_name = project.get('name')
            # 获取项目指定的remote，如果没有则使用默认remote
            project_remote = project.get('remote', default_remote)
            # 获取项目指定的revision，如果没有则使用默认revision
            project_revision = project.get('revision', default_revision)
            
            # 获取对应remote的fetch地址
            if project_remote not in remotes:
                print(f"警告: 项目 {project_name} 指定的remote '{project_remote}' 未定义，跳过该项目")
                continue
                
            remote_fetch = remotes[project_remote]
            
            # 构建完整的本地路径和远程仓库URL
            local_path = os.path.join(basepath, project_path)
            remote_url = f"{remote_fetch}/{project_name}"
            
            print(f"\n正在处理仓库: {project_name}")
            print(f"使用remote: {project_remote}")
            print(f"本地路径: {local_path}")
            print(f"远程URL: {remote_url}")
            print(f"分支: {project_revision}")
            
            # 确保目标目录存在
            os.makedirs(os.path.dirname(local_path), exist_ok=True)
            
            if not os.path.exists(local_path):
                # 如果目录不存在，执行git clone
                print(f"克隆仓库: {project_name}")
                subprocess.run(['git', 'clone', '-b', project_revision, remote_url, local_path], 
                             check=True)
            else:
                # 如果目录存在，执行git pull
                print(f"更新仓库: {project_name}")
                subprocess.run(['git', '-C', local_path, 'fetch'], check=True)
                subprocess.run(['git', '-C', local_path, 'checkout', project_revision], check=True)
                subprocess.run(['git', '-C', local_path, 'pull'], check=True)

            success_count += 1
                
        except subprocess.CalledProcessError as e:
            fail_count += 1
            error_msg = str(e)
            print(f"处理仓库 {project_name} 时发生错误: {error_msg}")
            fail_repos.append({
                'name': project_name,
                'url': remote_url,
            })
        except Exception as e:
            fail_count += 1
            error_msg = str(e)
            print(f"处理仓库 {project_name} 时发生未知错误: {error_msg}")
            fail_repos.append({
                'name': project_name,
                'url': remote_url,
            })
    
    # 输出统计结果
    print("\n\n\033[32m============= 执行结果统计 =============\033[0m")
    print(f"\033[32m总仓库数: {total_projects}\033[0m")
    print(f"\033[32m成功拉取: {success_count}\033[0m")
    
    if fail_count > 0:
        print(f"\033[31m失败数量: {fail_count}\033[0m")
        print("\n\033[31m失败仓库详细信息:\033[0m")
        for i, repo in enumerate(fail_repos, 1):
            print(f"\033[31m{i}. 仓库名称: {repo['name']}\033[0m")
            print(f"\033[31m   远程地址: {repo['url']}\033[0m\n")

def DownloadFileWithCurl(url, output_path='temp.xml'):
    """
    使用 curl 命令下载远程文件
    
    Args:
        url (str): 远程文件的 URL
        output_path (str): 保存到本地的路径
    
    Returns:
        str: 下载成功时返回本地路径，失败则退出程序
    """
    import subprocess
    result = subprocess.run(
        ['curl', '-o', output_path, url],
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE
    )
    if result.returncode != 0:
        print(f"下载文件失败: {result.stderr.decode()}")
        sys.exit(1)
    return output_path

if __name__ == "__main__":
    print("============= BEGIN: git_pull_xml.py =============")
    
    # 设置命令行参数解析器
    parser = argparse.ArgumentParser(description='从XML文件拉取多个Git仓库.')
    parser.add_argument('-b', '--basepath', type=str, required=True, help='本地仓库的基础目录路径')
    parser.add_argument('-x', '--xmlpath', type=str, required=True, help='包含仓库信息的XML文件路径')
    
    # 解析命令行参数
    args = parser.parse_args()

    xmlpath = args.xmlpath

    if not os.path.exists(xmlpath):
        xmlpath = DownloadFileWithCurl(xmlpath, f'{SCRIPT_DIR}/temp.xml')
        
    # 执行仓库拉取
    GitPullXml(args.basepath, xmlpath)
    
    print("============= END: git_pull_xml.py =============\n\n")



